/*
PearReview - The peer review assistant.
Copyright (C) 2009  Dimitrij Pankratz, Anton Musichin
http://www.pearreview.com, info@pearreview.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package com.pearreview.scribeplugin;

import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorEvent;
import java.awt.datatransfer.FlavorListener;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableRowSorter;

import com.pearreview.ui.*;
import com.pearreview.ui.accordion.Accordion;
import com.pearreview.ui.clock.ScribeClock;
import com.pearreview.ui.list.DefaultAdvancedListCellRenderer;
import com.pearreview.ui.list.ImageListCellRenderer;
import com.pearreview.ui.table.FindingListRenderer;
import com.pearreview.ui.table.FindingTableModel;
import com.pearreview.ui.table.IdItemTableCellRenderer;
import com.pearreview.ui.table.SeverityTableCellRenderer;
import com.pearreview.ui.table.DefaultAdvancedTableCellRenderer;
import com.pearreview.ui.table.ToolTipJTable;
import com.pearreview.application.Messages;
import com.pearreview.application.SpringGlassPane;
import com.pearreview.util.DoubleClickMouseAdapter;
import com.pearreview.util.ImageFileFilter;
import com.pearreview.util.review.AbstractIdItem;
import com.pearreview.util.review.Aspect;
import com.pearreview.util.review.Finding;
import com.pearreview.util.review.IdComparator;
import com.pearreview.util.review.IdList;
import com.pearreview.util.review.Severity;

public class FindingsPanel extends PearPanel implements ScribePanel {
	
	private static final long serialVersionUID = 1307905773711579035L;
	
	private static final String CATEGORY_ASPECT_SEPARATOR = " > ";
	
	private static final int ROW_SPACE = 8;
	
	/* index of id column, needed to setup row sorter */
	private static final int ID_COLUMN_INDEX = 0;
	
	private FormLabel descriptionLabel;
	private JScrollPane scrollPaneDescription;
	private FadingTextArea description;
	private FormLabel severityLabel;
	private JComboBox severity;
	private JButton addBtn;
	private JScrollPane scrollPaneTable;
	private JTable findingsTable;
	private JScrollPane scrollPaneAspects;
	private JList aspectsList;
	private DefaultListModel aspectsListModel;
	private JButton addAspectBtn;
	private CompletableJTextField aspectField;
	private JScrollPane scrollPaneScreenshot;
	private JList screenshotList;
	private JButton addScreenshotBtn;
	private JButton addClipboardScreenBtn;
	private Action addClipboardImageAction = new AddClipboardImageAction();
	private GroupLayout layout;
	private JPanel formPanel;
	private File lastDir;
	private DefaultListModel imagesModel;
	private JButton deleteScreenshotBtn;
	private JButton showScreenshotBtn;
	private JButton deleteAspectBtn;
	private DeleteImageAction deleteImageAction;
	private ShowImageAction showImageAction;
	private CompletableJTextField reference;
	private FormLabel referenceLabel;
	private Accordion accordion;
	
	//edit form
	private FormLabel descriptionLabelEdit;
	private JScrollPane scrollPaneDescriptionEdit;
	private FadingTextArea descriptionEdit;
	private FormLabel severityLabelEdit;
	private JComboBox severityEdit;
	private JButton addBtnEdit;
	private JButton abortEdit;
	private JScrollPane scrollPaneAspectsEdit;
	private JList aspectsListEdit;
	private DefaultListModel aspectsListModelEdit;
	private JButton addAspectBtnEdit;
	private CompletableJTextField aspectFieldEdit;
	private JScrollPane scrollPaneScreenshotEdit;
	private JList screenshotListEdit;
	private JButton addScreenshotBtnEdit;
	private JButton addClipboardScreenBtnEdit;
	private DefaultListModel imagesModelEdit;
	private JButton deleteScreenshotBtnEdit;
	private JButton showScreenshotBtnEdit;
	private JButton deleteAspectBtnEdit;
	private CompletableJTextField referenceEdit;
	private FormLabel referenceLabelEdit;
	private Accordion accordionEdit;
	
	private JPanel newForm = new JPanel();
	private JPanel editForm = new JPanel();
	
	private FindingTableModel findingModel = new FindingTableModel();
	private Action deleteAction = new DeleteAction();
	private Action editAction = new EditAction();
	
	private HeadingLabel headingLabel;
	private Finding editFinding;
	private int editFindingIndex;
	
	private JButton editFindingBtn;
	private JButton deleteFindingBtn;
	
	private boolean editMode = false;
	
	private int aspectNum = 0;
	private BottomButtonPanel bottom;
	
	private TableRowSorter<FindingTableModel> rowSorter;
	
	private int severityHeight;
	
	/**
	 * If user adds a new finding, this fild be increase by one
	 * and sets it as id of new finding
	 */
	private int currentFindingId = 0;
	
	private List<Severity> severities;
	
	private URI imageIsShown = null;
	
	private SpringGlassPane glassPane;
	
	public FindingsPanel(SpringGlassPane glassPane) {
		this.glassPane = glassPane;
		initComponents();
	}
	
	private void resizeFindingsTableColumns() {
		TableColumnModel columnModel = findingsTable.getColumnModel();
		int preferredWidth = findingsTable.getSize().width;
		double[] columnSizes = {0.05, 0.55, 0.10, 0.10, 0.10, 0.10};
		for(int i = 0 ; i < columnModel.getColumnCount() ; i++) {
			TableColumn column = columnModel.getColumn(i);
			column.setPreferredWidth(
					(int) (columnSizes[i] * preferredWidth));
		}
	}

	private void initComponents() {
		descriptionLabel = new FormLabel();
		scrollPaneDescription = new JScrollPane();
		description = new FadingTextArea();
		severityLabel = new FormLabel();
		severity = new JComboBox();
		addBtn = new JButton();
		scrollPaneTable = new JScrollPane();
		findingsTable = new ToolTipJTable();
		
		scrollPaneAspects = new JScrollPane();
		aspectsList = new JList();
		addAspectBtn = new JButton();
		aspectField = new CompletableJTextField();
		aspectsListModel = new DefaultListModel();
		
		scrollPaneScreenshot = new JScrollPane();
		screenshotList = new JList();
		addScreenshotBtn = new JButton();
		addClipboardScreenBtn = new JButton();
		imagesModel = new DefaultListModel();
		deleteScreenshotBtn = new JButton();
		showScreenshotBtn = new JButton();
		deleteAspectBtn = new JButton();
		deleteImageAction = new DeleteImageAction();
		showImageAction = new ShowImageAction();

		reference = new CompletableJTextField();
		referenceLabel = new FormLabel(Messages.getString(
				"PearReview.Scribe.findings.reference"));
		
		descriptionLabelEdit = new FormLabel();
		scrollPaneDescriptionEdit = new JScrollPane();
		descriptionEdit = new FadingTextArea();
		severityLabelEdit = new FormLabel();
		severityEdit = new JComboBox();
		addBtnEdit = new JButton();
		abortEdit = new JButton();
		
		scrollPaneAspectsEdit = new JScrollPane();
		aspectsListEdit = new JList();
		addAspectBtnEdit = new JButton();
		aspectFieldEdit = new CompletableJTextField();
		aspectsListModelEdit = new DefaultListModel();
		
		scrollPaneScreenshotEdit = new JScrollPane();
		screenshotListEdit = new JList();
		addScreenshotBtnEdit = new JButton();
		addClipboardScreenBtnEdit = new JButton();
		imagesModelEdit = new DefaultListModel();
		deleteScreenshotBtnEdit = new JButton();
		showScreenshotBtnEdit = new JButton();
		deleteAspectBtnEdit = new JButton();
		
		referenceEdit = new CompletableJTextField();
		referenceLabelEdit = new FormLabel(Messages.getString(
				"PearReview.Scribe.findings.reference"));
		
		editFindingBtn = new JButton();
		deleteFindingBtn = new JButton();
		
		

		//======== this ========
		setLayout(new BorderLayout());
		//setPreferredSize(new Dimension(650,550));
		
		deleteAction.setEnabled(false);
		editAction.setEnabled(false);

		//---- descriptionLabel ----
		descriptionLabel.setText(Messages.getString(
				"PearReview.Scribe.findings.description"));

		//======== scrollPaneDescription ========
		{
			scrollPaneDescription.setViewportView(description);
		}

		//---- severityLabel ----
		severityLabel.setText(Messages.getString(
				"PearReview.Scribe.findings.severity"));

		//---- severity ----
		severity.setEditable(true);
		FadingManager.getInstance().registerComponent(severity);
		severity.setFont(new Font("Tahoma", Font.PLAIN, 12));
		severityHeight = GroupLayout.PREFERRED_SIZE;
		if (System.getProperty("os.name").equals("Mac OS X")) {
			JComponent editor = 
				(JComponent) severity.getEditor().getEditorComponent();
			editor.setBorder(BorderFactory.createMatteBorder(
						1, 1, 1, 1, new Color(0x828790)));
			severityHeight = 20;
		} else {
			severity.setBorder(BorderFactory.createMatteBorder(
							1, 1, 1, 1, new Color(0x828790)));
		}
		
		//---- addBtn ----
		addBtn.setAction(new AddFindingAction());
		addBtn.setText(Messages.getString(
				"PearReview.Scribe.findings.add_finding"));
		addBtn.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- editFindingBtn ----
		editFindingBtn.setAction(editAction);
		editFindingBtn.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- deleteFindingBtn ----
		deleteFindingBtn.setAction(deleteAction);
		deleteFindingBtn.setFont(new Font("Tahoma", Font.PLAIN, 12));

		//======== scrollPaneTable ========
		{
			scrollPaneTable.setBorder(BorderFactory.createMatteBorder(
					1, 1, 1, 1, new Color(0x828790)));
			scrollPaneTable.setViewportView(findingsTable);
			scrollPaneTable.setOpaque(false);
			//scrollPaneTable.setBackground(new Color(0x808080));
			scrollPaneTable.getViewport().setOpaque(false);

			//---- findingsTable ----
			findingsTable.setFont(new Font("Tahoma", Font.PLAIN, 12));
			findingsTable.setPreferredScrollableViewportSize(
					new Dimension(250, 100));
			
			/* install row sorter */
			//findingsTable.setAutoCreateRowSorter(true);
			rowSorter = new TableRowSorter<FindingTableModel>(findingModel);
			rowSorter.setSortsOnUpdates(true);
			rowSorter.setComparator(ID_COLUMN_INDEX, new IdComparator());
			RowSorter.SortKey idSortKey = new RowSorter.SortKey(
					ID_COLUMN_INDEX, SortOrder.DESCENDING);
			rowSorter.setSortKeys(Arrays.asList(idSortKey));
			
			findingsTable.setModel(findingModel);
			findingsTable.setRowSorter(rowSorter);
			findingsTable.setOpaque(false);
			findingsTable.setSelectionBackground(new Color(0xbfd72b));
			findingsTable.setFont(new Font("Tahoma", Font.PLAIN, 12));
			findingsTable.getTableHeader().setFont(
					new Font("Tahoma", Font.PLAIN, 12));
			
			TableSelectionListener tsl = new TableSelectionListener();
			findingsTable.getSelectionModel().addListSelectionListener(tsl);
			findingsTable.getColumnModel().getSelectionModel()
					.addListSelectionListener(tsl);
			
			//findingsTable.getSelectionModel().setSelectionMode(
			//		ListSelectionModel.SINGLE_SELECTION);
			
			SeverityTableCellRenderer severityRenderer = 
					new SeverityTableCellRenderer();
			findingsTable.addMouseListener(severityRenderer);
			findingsTable.addMouseMotionListener(severityRenderer);
			findingsTable.setDefaultRenderer(Severity.class, severityRenderer);
			
			FindingListRenderer findingsRenderer = new FindingListRenderer();
			findingsTable.addMouseListener(findingsRenderer);
			findingsTable.addMouseMotionListener(findingsRenderer);
			findingsTable.setDefaultRenderer(List.class, findingsRenderer);
			
			IdItemTableCellRenderer idRenderer = new IdItemTableCellRenderer();
			findingsTable.addMouseListener(idRenderer);
			findingsTable.addMouseMotionListener(idRenderer);
			findingsTable.setDefaultRenderer(AbstractIdItem.class, idRenderer);
			
			DefaultAdvancedTableCellRenderer defaultRenderer = 
					new DefaultAdvancedTableCellRenderer();
			findingsTable.addMouseListener(defaultRenderer);
			findingsTable.addMouseMotionListener(defaultRenderer);
			findingsTable.setDefaultRenderer(String.class, defaultRenderer);
			
			findingsTable.addComponentListener(new ComponentAdapter() {
				public void componentResized(ComponentEvent e) {
					resizeFindingsTableColumns();
					e.getComponent().removeComponentListener(this);
				}
			});
			
			
			findingsTable.addMouseListener(new DoubleClickMouseAdapter() {
				private static final long serialVersionUID = 
						5852815395754205830L;
				@Override
				public void mouseDoubleClicked(MouseEvent e) {
					editAction.actionPerformed(null);
				}
			});
			
			final JPopupMenu popup = new JPopupMenu();
			findingsTable.addMouseListener(new MouseAdapter() {
				private void popup(MouseEvent e) {
					int row = findingsTable.rowAtPoint(e.getPoint());
						
					ListSelectionModel selectionModel = 
							findingsTable.getSelectionModel();
					
					if(!findingsTable.isRowSelected(row))
						selectionModel.setSelectionInterval(row, row);
					
					popup.removeAll();
					
					if(editAction.isEnabled())
						popup.add(editAction);
					if(deleteAction.isEnabled())
						popup.add(deleteAction);
					
					if(popup.getComponentCount() > 0)
						popup.show(e.getComponent(),
									e.getPoint().x,
									e.getPoint().y);
				}
				@Override
				public void mousePressed(MouseEvent e) {
					if (e.isPopupTrigger()) {
						popup(e);
					}
				}
				@Override
				public void mouseReleased(MouseEvent e) {
					if (e.isPopupTrigger()) {
						popup(e);
				 	}
				}
			});
		}
		
		updateFindingsTableRowHeight();
		
		//---- aspectsList ---- 
		DefaultAdvancedListCellRenderer aRenderer = 
				new DefaultAdvancedListCellRenderer();
		aspectsList.addMouseListener(aRenderer);
		aspectsList.addMouseMotionListener(aRenderer);
		aspectsList.setCellRenderer(aRenderer);
		aspectsList.setModel(aspectsListModel);
		aspectsList.setFont(new Font("Tahoma", Font.PLAIN, 12));
		aspectsList.setSelectionBackground(new Color(0xbfd72b));
		aspectsList.getSelectionModel().setSelectionMode(
				ListSelectionModel.SINGLE_SELECTION);

		//======== scrollPaneAspects ========
		{
			scrollPaneAspects.setViewportView(aspectsList);
			scrollPaneAspects.setBorder(BorderFactory.createMatteBorder(
					1, 1, 1, 1, new Color(0x828790)));
			//scrollPane3.setPreferredSize(new Dimension(150,100));
		}

		//---- addAspectBtn ----
		addAspectBtn.setAction(new AddAspectAction());
		addAspectBtn.setText(Messages.getString(
				"PearReview.Scribe.findings.add_aspect"));
		addAspectBtn.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- deleteAspectBtn ----
		deleteAspectBtn.setAction(new DeleteAspectAction());
		deleteAspectBtn.setText(Messages.getString(
				"PearReview.Scribe.findings.delete_aspect"));
		deleteAspectBtn.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		
		//---- screenshotList ---- 
		screenshotList.setCellRenderer(new ImageListCellRenderer());
		screenshotList.setSelectionBackground(new Color(0xbfd72b));
		screenshotList.setModel(imagesModel);
		screenshotList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
		screenshotList.setVisibleRowCount(-1);
		screenshotList.addListSelectionListener(new ScreenshotListener());
		screenshotList.addMouseListener(new DoubleClickMouseAdapter(){
			private static final long serialVersionUID = -4102832207732360870L;
			@Override
			public void mouseDoubleClicked(MouseEvent e) {
				ActionEvent event = new ActionEvent(e.getSource(), 
						ActionEvent.ACTION_PERFORMED, 
						"showImage");
				showImageAction.actionPerformed(event);
			}
		});
		//screenshotList.setPreferredSize(new Dimension(150,100));

		//======== scrollPaneScreenshot ========
		{
			scrollPaneScreenshot.setViewportView(screenshotList);
			scrollPaneScreenshot.setBorder(BorderFactory.createMatteBorder(
					1, 1, 1, 1, new Color(0x828790)));
			//scrollPane4.setPreferredSize(new Dimension(150,100));
		}

		//---- addScreenshotBtn ----
		addScreenshotBtn.setAction(new AddImageAction());
		addScreenshotBtn.setText(Messages.getString(
				"PearReview.Scribe.findings.add_image"));
		addScreenshotBtn.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- addClipboardScreenBtn ----
		addClipboardScreenBtn.setAction(addClipboardImageAction);
		addClipboardScreenBtn.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- deleteImageAction ----
		deleteImageAction.setEnabled(false);
		
		//---- deleteScreenshotBtn ----
		deleteScreenshotBtn.setAction(deleteImageAction);
		deleteScreenshotBtn.setText(Messages.getString(
				"PearReview.Scribe.findings.delete_image"));
		deleteScreenshotBtn.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- showImageAction ----
		showImageAction.setEnabled(false);
		
		//---- showScreenshotBtn ----
		showScreenshotBtn.setAction(showImageAction);
		showScreenshotBtn.setText(Messages.getString(
				"PearReview.Scribe.findings.show_image"));
		showScreenshotBtn.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		JPanel aspectPanel = new JPanel();
		aspectPanel.setOpaque(false);

		GroupLayout aspectLayout = new GroupLayout(aspectPanel);
		aspectPanel.setLayout(aspectLayout);
		aspectLayout.setHorizontalGroup(
				aspectLayout.createParallelGroup()
				.addComponent(aspectField)
				.addGroup(aspectLayout.createParallelGroup()
						.addGroup(aspectLayout.createSequentialGroup()
								.addComponent(addAspectBtn)
								.addGap(10)
								.addComponent(deleteAspectBtn)))
				.addComponent(scrollPaneAspects));
		aspectLayout.setVerticalGroup(
				aspectLayout.createSequentialGroup()
				.addGap(10)
				.addComponent(aspectField,
						GroupLayout.PREFERRED_SIZE,
						GroupLayout.PREFERRED_SIZE,
						GroupLayout.PREFERRED_SIZE)
				.addGap(10)
				.addGroup(aspectLayout.createParallelGroup()
						.addComponent(addAspectBtn)
						.addComponent(deleteAspectBtn))
				.addGap(10)
				.addComponent(scrollPaneAspects)
				.addGap(10));
		
	  //---- screenshotPanel ----
		JPanel screenshotPanel = new JPanel();
		screenshotPanel.setOpaque(false);

		GroupLayout screenshotLayout = new GroupLayout(screenshotPanel);
		screenshotPanel.setLayout(screenshotLayout);
		screenshotLayout.setHorizontalGroup(
				screenshotLayout.createParallelGroup()
				.addComponent(scrollPaneScreenshot)
				.addGroup(screenshotLayout.createParallelGroup()
						.addGroup(screenshotLayout.createSequentialGroup()
								.addComponent(addScreenshotBtn)
								.addGap(10)
								.addComponent(addClipboardScreenBtn))
						.addGroup(screenshotLayout.createSequentialGroup()
								.addComponent(showScreenshotBtn)
								.addGap(10)
								.addComponent(deleteScreenshotBtn))
								));
		screenshotLayout.setVerticalGroup(
				screenshotLayout.createSequentialGroup()
				.addGap(10)
				.addComponent(scrollPaneScreenshot)
				.addGap(10)
				.addGroup(screenshotLayout.createParallelGroup()
						.addComponent(addScreenshotBtn)
						.addComponent(addClipboardScreenBtn))
				.addGap(10)
				.addGroup(screenshotLayout.createParallelGroup()
						.addComponent(showScreenshotBtn)
						.addComponent(deleteScreenshotBtn)));
		
		
		accordion = new Accordion();
		//accordion.addBar(Messages.getString(
		//		"PearReview.Scribe.findings.reference"), referencePanel);
		accordion.addBar(Messages.getString(
				"PearReview.Scribe.findings.aspects"), aspectPanel);
		accordion.addBar(Messages.getString(
				"PearReview.Scribe.findings.images"), screenshotPanel);
		accordion.setPreferredSize(new Dimension(150,150));
		
		JPanel container = new JPanel();
		container.setOpaque(false);
		container.setBorder(BorderFactory.createMatteBorder(
	  			1, 1, 1, 1, new Color(0x828790)));
		container.setPreferredSize(new Dimension(200,250));
		
		GroupLayout containerLayout = new GroupLayout(container);
		container.setLayout(containerLayout);
		containerLayout.setHorizontalGroup(
				containerLayout.createParallelGroup()
				.addComponent(accordion));
		containerLayout.setVerticalGroup(
				containerLayout.createSequentialGroup()
				.addComponent(accordion));
		
		
		
		
		//edit components
		//---- descriptionLabelEdit ----
		descriptionLabelEdit.setText(Messages.getString(
				"PearReview.Scribe.findings.description"));

		//======== scrollPaneDescriptionEdit ========
		{
			scrollPaneDescriptionEdit.setViewportView(descriptionEdit);
		}

		//---- severityLabelEdit ----
		severityLabelEdit.setText(Messages.getString(
				"PearReview.Scribe.findings.severity"));

		//---- severityEdit ----
		severityEdit.setEditable(true);
		FadingManager.getInstance().registerComponent(severityEdit);
		severityEdit.setFont(new Font("Tahoma", Font.PLAIN, 12));
		if (System.getProperty("os.name").equals("Mac OS X")) {
			JComponent editor = 
					(JComponent) severityEdit.getEditor().getEditorComponent();
			editor.setBorder(BorderFactory.createMatteBorder(
							1, 1, 1, 1, new Color(0x828790)));
		} else {
			severityEdit
			.setBorder(BorderFactory.createMatteBorder(
							1, 1, 1, 1, new Color(0x828790)));
		}

		//---- addBtnEdit ----
		addBtnEdit.setAction(new EndEditAction());
		addBtnEdit.setText(Messages.getString(
				"PearReview.Scribe.findings.save"));
		addBtnEdit.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- abortEdit ----
		abortEdit.setAction(new AbortEditAction());
		abortEdit.setText(Messages.getString(
				"PearReview.Scribe.findings.abort"));
		abortEdit.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- aspectsListEdit ---- 
		DefaultAdvancedListCellRenderer aEditRenderer = 
				new DefaultAdvancedListCellRenderer();
		aspectsListEdit.addMouseListener(aEditRenderer);
		aspectsListEdit.addMouseMotionListener(aEditRenderer);
		aspectsListEdit.setCellRenderer(aEditRenderer);
		aspectsListEdit.setModel(aspectsListModelEdit);
		aspectsListEdit.setFont(new Font("Tahoma", Font.PLAIN, 12));
		aspectsListEdit.setSelectionBackground(new Color(0xbfd72b));
		aspectsListEdit.getSelectionModel().setSelectionMode(
				ListSelectionModel.SINGLE_SELECTION);

		//======== scrollPaneAspectsEdit ========
		{
			scrollPaneAspectsEdit.setViewportView(aspectsListEdit);
			scrollPaneAspectsEdit.setBorder(BorderFactory.createMatteBorder(
					1, 1, 1, 1, new Color(0x828790)));
		}

		//---- addAspectBtnEdit ----
		addAspectBtnEdit.setAction(new AddAspectAction());
		addAspectBtnEdit.setText(Messages.getString(
				"PearReview.Scribe.findings.add_aspect"));
		addAspectBtnEdit.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- deleteAspectBtnEdit ----
		deleteAspectBtnEdit.setAction(new DeleteAspectAction());
		deleteAspectBtnEdit.setText(Messages.getString(
				"PearReview.Scribe.findings.delete_aspect"));
		deleteAspectBtnEdit.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		
		//---- screenshotListEdit ---- 
		screenshotListEdit.setCellRenderer(new ImageListCellRenderer());
		screenshotListEdit.setSelectionBackground(new Color(0xbfd72b));
		screenshotListEdit.setModel(imagesModelEdit);
		screenshotListEdit.addListSelectionListener(new ScreenshotListener());
		screenshotListEdit.setLayoutOrientation(JList.HORIZONTAL_WRAP);
		screenshotListEdit.setVisibleRowCount(-1);
		screenshotListEdit.addMouseListener(new DoubleClickMouseAdapter(){
			private static final long serialVersionUID = -4102832207732360870L;
			@Override
			public void mouseDoubleClicked(MouseEvent e) {
				ActionEvent event = new ActionEvent(e.getSource(), 
						ActionEvent.ACTION_PERFORMED, 
						"showImage");
				showImageAction.actionPerformed(event);
			}
		});
		//screenshotList.setPreferredSize(new Dimension(150,100));

		//======== scrollPaneScreenshotEdit ========
		{
			scrollPaneScreenshotEdit.setViewportView(screenshotListEdit);
			scrollPaneScreenshotEdit.setBorder(BorderFactory.createMatteBorder(
					1, 1, 1, 1, new Color(0x828790)));
		}

		//---- addScreenshotBtnEdit ----
		addScreenshotBtnEdit.setAction(new AddImageAction());
		addScreenshotBtnEdit.setText(Messages.getString(
				"PearReview.Scribe.findings.add_image"));
		addScreenshotBtnEdit.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- addClipboardScreenBtnEdit ----
		addClipboardScreenBtnEdit.setAction(addClipboardImageAction);
		addClipboardScreenBtnEdit.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- deleteScreenshotBtnEdit ----
		deleteScreenshotBtnEdit.setAction(deleteImageAction);
		deleteScreenshotBtnEdit.setText(Messages.getString(
				"PearReview.Scribe.findings.delete_image"));
		deleteScreenshotBtnEdit.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		//---- showScreenshotBtnEdit ----
		showScreenshotBtnEdit.setAction(showImageAction);
		showScreenshotBtnEdit.setText(Messages.getString(
				"PearReview.Scribe.findings.show_image"));
		showScreenshotBtnEdit.setFont(new Font("Tahoma", Font.PLAIN, 12));
		
		
		//---- referenceScrollPaneEdit ----
		//referenceScrollPaneEdit.setViewportView(referenceListEdit);
		
		//---- referenceListEdit ----
		//referenceListEdit.setBorder(null);
		
		
		//---- referencePanelEdit ----
		/*
		JPanel referencePanelEdit = new JPanel();
		referencePanelEdit.setOpaque(false);

		GroupLayout referenceLayoutEdit = new GroupLayout(referencePanelEdit);
		referencePanelEdit.setLayout(referenceLayoutEdit);
		referenceLayoutEdit.setHorizontalGroup(
				referenceLayoutEdit.createParallelGroup()
				.addComponent(referenceScrollPaneEdit)
				.addGroup(referenceLayoutEdit.createParallelGroup()
						));
		referenceLayoutEdit.setVerticalGroup(
				referenceLayoutEdit.createSequentialGroup()
				.addGap(10)
				.addComponent(referenceScrollPaneEdit)
				.addGap(10));
				*/
		
		
		//---- aspectPanelEdit ----
		JPanel aspectPanelEdit = new JPanel();
		aspectPanelEdit.setOpaque(false);

		GroupLayout aspectLayoutEdit = new GroupLayout(aspectPanelEdit);
		aspectPanelEdit.setLayout(aspectLayoutEdit);
		aspectLayoutEdit.setHorizontalGroup(
				aspectLayoutEdit.createParallelGroup()
				.addComponent(aspectFieldEdit)
				.addGroup(aspectLayoutEdit.createParallelGroup()
						.addGroup(aspectLayoutEdit.createSequentialGroup()
								.addComponent(addAspectBtnEdit)
								.addGap(10)
								.addComponent(deleteAspectBtnEdit)))
				.addComponent(scrollPaneAspectsEdit));
		
		aspectLayoutEdit.setVerticalGroup(
				aspectLayoutEdit.createSequentialGroup()
				.addGap(10)
				.addComponent(aspectFieldEdit,
						GroupLayout.PREFERRED_SIZE,
						GroupLayout.PREFERRED_SIZE,
						GroupLayout.PREFERRED_SIZE)
				.addGap(10)
				.addGroup(aspectLayoutEdit.createParallelGroup()
						.addComponent(addAspectBtnEdit)
						.addComponent(deleteAspectBtnEdit))
				.addGap(10)
				.addComponent(scrollPaneAspectsEdit)
				.addGap(10));
		
	  //---- screenshotPanelEdit ----
		JPanel screenshotPanelEdit = new JPanel();
		screenshotPanelEdit.setOpaque(false);

		GroupLayout screenshotLayoutEdit = new GroupLayout(screenshotPanelEdit);
		screenshotPanelEdit.setLayout(screenshotLayoutEdit);
		screenshotLayoutEdit.setHorizontalGroup(
				screenshotLayoutEdit.createParallelGroup()
				.addComponent(scrollPaneScreenshotEdit)
				.addGroup(screenshotLayoutEdit.createParallelGroup()
						.addGroup(screenshotLayoutEdit.createSequentialGroup()
								.addComponent(addScreenshotBtnEdit)
								.addGap(10)
								.addComponent(addClipboardScreenBtnEdit))
						.addGroup(screenshotLayoutEdit.createSequentialGroup()
								.addComponent(showScreenshotBtnEdit)
								.addGap(10)
								.addComponent(deleteScreenshotBtnEdit))
								));
		
		screenshotLayoutEdit.setVerticalGroup(
				screenshotLayoutEdit.createSequentialGroup()
				.addGap(10)
				.addComponent(scrollPaneScreenshotEdit)
				.addGap(10)
				.addGroup(screenshotLayoutEdit.createParallelGroup()
						.addComponent(addScreenshotBtnEdit)
						.addComponent(addClipboardScreenBtnEdit))
				.addGap(10)
				.addGroup(screenshotLayoutEdit.createParallelGroup()
						.addComponent(showScreenshotBtnEdit)
						.addComponent(deleteScreenshotBtnEdit)));
		
		
		accordionEdit = new Accordion();
		//accordionEdit.addBar(Messages.getString(
		//		"PearReview.Scribe.findings.reference"), referencePanelEdit);
		accordionEdit.addBar(Messages.getString(
				"PearReview.Scribe.findings.aspects"), aspectPanelEdit);
		accordionEdit.addBar(Messages.getString(
				"PearReview.Scribe.findings.images"), screenshotPanelEdit);
		accordionEdit.setPreferredSize(new Dimension(150,150));
		
		JPanel containerEdit = new JPanel();
		containerEdit.setOpaque(false);
		containerEdit.setBorder(BorderFactory.createMatteBorder(
	  			1, 1, 1, 1, new Color(0x828790)));
		containerEdit.setPreferredSize(new Dimension(200,250));
		
		GroupLayout containerLayoutEdit = new GroupLayout(containerEdit);
		containerEdit.setLayout(containerLayoutEdit);
		containerLayoutEdit.setHorizontalGroup(
				containerLayoutEdit.createParallelGroup()
				.addComponent(accordionEdit));
		containerLayoutEdit.setVerticalGroup(
				containerLayoutEdit.createSequentialGroup()
				.addComponent(accordionEdit));
		
		
		
		
		
		
		
		
		
		
		
		
		editForm.setOpaque(false);
		GroupLayout editLayout = new GroupLayout(editForm);
		

		editForm.setLayout(editLayout);
		editLayout.setHorizontalGroup(
				editLayout.createParallelGroup()
				.addGroup(editLayout.createSequentialGroup()
					.addContainerGap()
					.addGroup(editLayout.createParallelGroup()
						.addGroup(editLayout.createSequentialGroup()
							.addGroup(editLayout.createParallelGroup()
								.addComponent(descriptionLabelEdit, 
										GroupLayout.PREFERRED_SIZE, 
										80, 
										GroupLayout.PREFERRED_SIZE)
								.addComponent(severityLabelEdit, 
										GroupLayout.PREFERRED_SIZE, 
										80, 
										GroupLayout.PREFERRED_SIZE)
								.addComponent(referenceLabelEdit, 
										GroupLayout.PREFERRED_SIZE, 
										80, 
										GroupLayout.PREFERRED_SIZE))
							.addGap(57, 57, 57)
							.addGroup(editLayout.createParallelGroup()
								.addGroup(editLayout.createSequentialGroup()
									.addGroup(editLayout.createParallelGroup()
											.addGroup(
											editLayout.createParallelGroup()
											.addGroup(
											editLayout.createSequentialGroup()
													.addComponent(addBtnEdit)
													.addGap(10)
													.addComponent(abortEdit)))
										.addComponent(referenceEdit, 
												100, 
												150, 
												Short.MAX_VALUE)
										.addComponent(severityEdit, 
												100, 
												150, 
												Short.MAX_VALUE)
										.addComponent(scrollPaneDescriptionEdit, 
												GroupLayout.DEFAULT_SIZE, 
												150, 
												Short.MAX_VALUE))
										)))).addGap(30)
									.addGroup(
										editLayout.createSequentialGroup()
											.addGroup(
												editLayout.createParallelGroup(
											GroupLayout.Alignment.LEADING, 
											false)
										.addComponent(containerEdit,
												300,
												300,
												Short.MAX_VALUE)))
										.addGap(10)
										
					)
					
		);
		
		editLayout.setVerticalGroup(
				editLayout.createParallelGroup()
					.addGroup(editLayout.createSequentialGroup()
						.addContainerGap()
							.addGroup(editLayout.createParallelGroup()
								.addGroup(editLayout.createSequentialGroup()
									.addGroup(editLayout.createParallelGroup()
										.addComponent(scrollPaneDescriptionEdit,
												100, 
												100, 
												Short.MAX_VALUE)
										.addComponent(descriptionLabelEdit, 
												GroupLayout.PREFERRED_SIZE, 
												GroupLayout.DEFAULT_SIZE, 
												GroupLayout.PREFERRED_SIZE))
									.addGap(10)
									.addGroup(editLayout.createParallelGroup()
										.addComponent(severityLabelEdit, 
												GroupLayout.PREFERRED_SIZE, 
												GroupLayout.DEFAULT_SIZE, 
												GroupLayout.PREFERRED_SIZE)
										.addComponent(severityEdit, 
												severityHeight, 
												GroupLayout.PREFERRED_SIZE, 
												GroupLayout.PREFERRED_SIZE))
									.addGap(10)
									.addGroup(editLayout.createParallelGroup()
										.addComponent(referenceLabelEdit, 
												GroupLayout.PREFERRED_SIZE, 
												GroupLayout.DEFAULT_SIZE, 
												GroupLayout.PREFERRED_SIZE)
										.addComponent(referenceEdit, 
												GroupLayout.PREFERRED_SIZE, 
												GroupLayout.DEFAULT_SIZE, 
												GroupLayout.PREFERRED_SIZE))
									.addGap(10)
									.addGroup(editLayout.createParallelGroup()
											.addComponent(addBtnEdit)
											.addComponent(abortEdit)))
								.addGap(20)
								.addComponent(containerEdit))
						.addGap(30)));
		
		
		newForm.setOpaque(false);
		GroupLayout newLayout = new GroupLayout(newForm);
		

		newForm.setLayout(newLayout);
		newLayout.setHorizontalGroup(
				newLayout.createParallelGroup()
				.addGroup(newLayout.createSequentialGroup()
					.addContainerGap()
					.addGroup(newLayout.createParallelGroup()
						.addGroup(newLayout.createSequentialGroup()
							.addGroup(newLayout.createParallelGroup()
								.addComponent(descriptionLabel, 
										GroupLayout.PREFERRED_SIZE, 
										80, 
										GroupLayout.PREFERRED_SIZE)
								.addComponent(severityLabel, 
										GroupLayout.PREFERRED_SIZE, 
										80, 
										GroupLayout.PREFERRED_SIZE)
								.addComponent(referenceLabel, 
										GroupLayout.PREFERRED_SIZE, 
										80, 
										GroupLayout.PREFERRED_SIZE))
							.addGap(57, 57, 57)
									.addGroup(newLayout.createParallelGroup()
										.addGroup(
										newLayout.createParallelGroup()
										.addGroup(
										newLayout.createSequentialGroup()
												.addComponent(addBtn)
												.addGap(10)
												.addComponent(editFindingBtn)
												.addGap(10)
												.addComponent(
														deleteFindingBtn)))
										.addComponent(reference, 
												100, 
												150, 
												Short.MAX_VALUE)
										.addComponent(severity, 
												100, 
												150, 
												Short.MAX_VALUE)
										.addComponent(scrollPaneDescription, 
												GroupLayout.DEFAULT_SIZE, 
												150, 
												Short.MAX_VALUE))))
					.addGap(30)
					.addGroup(newLayout.createSequentialGroup()
							.addGroup(
									newLayout.createParallelGroup(
									GroupLayout.Alignment.LEADING, 
									false)
							.addComponent(container,
									300,
									300,
									Short.MAX_VALUE)))
					.addGap(10)));
		
		newLayout.setVerticalGroup(
			newLayout.createParallelGroup()
				.addGroup(newLayout.createSequentialGroup()
					.addContainerGap()
						.addGroup(newLayout.createParallelGroup()
							.addGroup(newLayout.createSequentialGroup()
								.addGroup(newLayout.createParallelGroup()
									.addComponent(scrollPaneDescription,
											100, 
											100, 
											Short.MAX_VALUE)
									.addComponent(descriptionLabel, 
											GroupLayout.PREFERRED_SIZE, 
											GroupLayout.DEFAULT_SIZE, 
											GroupLayout.PREFERRED_SIZE))
								.addGap(10)
								.addGroup(newLayout.createParallelGroup()
									.addComponent(severityLabel, 
											GroupLayout.PREFERRED_SIZE, 
											GroupLayout.DEFAULT_SIZE, 
											GroupLayout.PREFERRED_SIZE)
									.addComponent(severity, 
											severityHeight, 
											GroupLayout.PREFERRED_SIZE, 
											GroupLayout.PREFERRED_SIZE))
								.addGap(10)
								.addGroup(newLayout.createParallelGroup()
									.addComponent(referenceLabel, 
											GroupLayout.PREFERRED_SIZE, 
											GroupLayout.DEFAULT_SIZE, 
											GroupLayout.PREFERRED_SIZE)
									.addComponent(reference, 
											GroupLayout.PREFERRED_SIZE, 
											GroupLayout.DEFAULT_SIZE, 
											GroupLayout.PREFERRED_SIZE))
								.addGap(10)
								.addGroup(newLayout.createParallelGroup()
										.addComponent(addBtn)
										.addComponent(editFindingBtn)
										.addComponent(deleteFindingBtn)))
							.addGap(20)
							.addComponent(container))
					.addGap(30)));
		
		
		formPanel = new JPanel();
		formPanel.setOpaque(false);
		
		layout = new GroupLayout(formPanel);

		setForm(newForm);
		
		add(formPanel, BorderLayout.CENTER);
		
		headingLabel = new HeadingLabel(Messages.getString(
				"PearReview.Scribe.tabs.findings"));
		
		add(headingLabel, BorderLayout.NORTH);
		
		bottom = new BottomButtonPanel();
		bottom.setFontSliderEnabled(true);
		bottom.addFontSliderChangeListener(new FontChangeListener());
		add(bottom, BorderLayout.SOUTH);
		

		
		/* add clip board listener */
		Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
		clipboard.addFlavorListener(new ImageFlavorListener());
		
	}
	
	private void setForm(JPanel panel) {
		formPanel.removeAll();
		
		formPanel.setLayout(layout);
		layout.setHorizontalGroup(
			layout.createParallelGroup()
				.addGroup(layout.createSequentialGroup()
						.addComponent(panel))		
				.addGroup(layout.createSequentialGroup()
						.addGap(10)
						.addComponent(scrollPaneTable, 
								GroupLayout.DEFAULT_SIZE, 
								200, 
								Short.MAX_VALUE)
						.addGap(10))
		);
		
		layout.setVerticalGroup(
			layout.createParallelGroup()
				.addGroup(layout.createSequentialGroup()
						.addComponent(panel,
								GroupLayout.DEFAULT_SIZE,
								GroupLayout.PREFERRED_SIZE,
								GroupLayout.PREFERRED_SIZE)
					.addComponent(scrollPaneTable, 
							GroupLayout.PREFERRED_SIZE, 
							GroupLayout.PREFERRED_SIZE, 
							Short.MAX_VALUE)
					.addGap(10)));
		
		updateFontSize();
	}
	
	/**
	 * Returns a severity for name. if a severity will be not found, 
	 * a new will be created with name and added to the comboboxes
	 * @param name name of severity
	 * @return severity with specified name
	 */
	protected Severity getSeverity(String name) {
		for(Severity severity: severities) {
			if(severity.getName().equals(name))
				return severity;
		}
		
		Severity newSeverity = new Severity();
		newSeverity.setName(name);
		
		severities.add(newSeverity);
		severity.addItem(newSeverity.getName());
		severityEdit.addItem(newSeverity.getName());
		
		return newSeverity;
	}
	
	@Override
	public boolean isValidForm() {
		return findingModel.getRowCount() > 0;
	}
	
	private boolean isClipboardImageAvailable() {
		try {
			Clipboard clipboard = 
					Toolkit.getDefaultToolkit().getSystemClipboard();
			return clipboard.isDataFlavorAvailable(DataFlavor.imageFlavor);
		} catch(Throwable e) {
			return false;
		}
	}
	
	/**
	 * Gets a new finding out of form.
	 * 
	 * @return
	 */
	private Finding getNewFinding() {
		Finding finding = new Finding();
		
		finding.setId(String.valueOf(++currentFindingId));
		
		//description
		finding.setDescription(description.getText());
		description.setText(null);
		
		//references
		List<String> references = new ArrayList<String>();
		if (!(reference.getText() == null || 
				reference.getText().equals("")))
			references.add(reference.getText());
		finding.setReferences(references);
		reference.setText(null);
		
		//aspects
		List<String> aspects = new ArrayList<String>();
		for (int i=0; i<aspectsListModel.getSize(); i++) {
			aspects.add((String)aspectsListModel.get(i));
		}
		aspectsListModel.clear();
		finding.setAspects(aspects);
		
		//severity
		String name = severity.getEditor().getItem().toString();
		finding.setSeverity(getSeverity(name));
		
		//external refernces
		List<URI> images = new ArrayList<URI>();
		for (int i=0; i<imagesModel.getSize(); i++) {
			images.add((URI)imagesModel.get(i));
		}
		imagesModel.clear();
		finding.setExternalReferences(images);
		
		return finding;
	}
	
	/**
	 * Gets an edited finding out of Form.
	 * 
	 * @return
	 */
	private Finding getEditFinding() {
		//description
		editFinding.setDescription(descriptionEdit.getText());
		
		//references
		List<String> references = new ArrayList<String>();
		if (!(referenceEdit.getText() == null || 
				referenceEdit.getText().equals("")))
			references.add(referenceEdit.getText());
		editFinding.setReferences(references);
		
		//aspects
		List<String> aspects = new ArrayList<String>();
		for (int i=0; i<aspectsListModelEdit.getSize(); i++) {
			aspects.add((String)aspectsListModelEdit.get(i));
		}
		aspectsListModelEdit.clear();
		editFinding.setAspects(aspects);
		
		//severity
		String name = severityEdit.getEditor().getItem().toString();
		editFinding.setSeverity(getSeverity(name));
		
		//external refernces
		List<URI> images = new ArrayList<URI>();
		for (int i=0; i<imagesModelEdit.getSize(); i++) {
			images.add((URI)imagesModelEdit.get(i));
		}
		imagesModelEdit.clear();
		editFinding.setExternalReferences(images);
		
		return editFinding;
	}
	
	/**
	 * Sets a finding for editing in the edit form.
	 * 
	 * @param finding
	 */
	private void setEditFinding(Finding finding) {
		//description
		descriptionEdit.setText(finding.getDescription());
		
		//references
		String referencesStr = new String();
		if (finding.getReferences() != null) {
			for (int i=0; i<finding.getReferences().size(); i++) {
				referencesStr += finding.getReferences().get(i);
				if (i != (finding.getReferences().size()-1))
					referencesStr += ", ";
			}
		}
		referenceEdit.setText(referencesStr);
		
		//aspects
		aspectsListModelEdit.clear();
		if (finding.getAspects() != null) {
			for (int i=0; i<finding.getAspects().size(); i++) {
				aspectsListModelEdit.addElement(finding.getAspects().get(i));
			}
		}
		
		//severity
		if (severities != null) {
			Severity sev = finding.getSeverity();
			severityEdit.setSelectedItem(sev.getName());
		}
		
		//external refernces
		imagesModelEdit.clear();
		if (finding.getExternalReferences() != null) {
			for (int i=0; i<finding.getExternalReferences().size(); i++) {
				imagesModelEdit.addElement(
						finding.getExternalReferences().get(i));
			}
		}
		
	}
	
	
	/**
	 * Sets the form to edit mode or normal mode.
	 * 
	 * @param edit
	 */
	private void setEditMode(boolean edit) {
		if(editMode == edit)
			return;
		
		editMode = edit;
		
		showImageAction.closeViewer();
		
		editAction.setEnabled(!editMode);
		deleteAction.setEnabled(!editMode);
		
		Accordion lastAccordion = editMode ? accordion : accordionEdit;
		Accordion newAccordion = editMode ? accordionEdit : accordion;
		
		newAccordion.setVisibleBar(lastAccordion.getVisibleBar());
	}
	
	public void setFindings(IdList<Finding> findings, int highestId) {
		currentFindingId = highestId;
		if(findings == null) {
			findingModel.clearFindings();
			return;
		}
		
		findingModel.setFindings(findings);
	}
	
	/**
	 * Sets the aspects to use them in the form.
	 * 
	 * @param aspects
	 */
	public void setAspects(IdList<Aspect> aspects) {
		for (Aspect aspect: aspects) {
			aspectField.addCompletion(aspect.getDirective());
			aspectFieldEdit.addCompletion(aspect.getDirective());
			
			if(aspect.getCategory()!= null && !aspect.getCategory().equals("")){
				aspectField.addCompletion(aspect.getCategory() + 
						CATEGORY_ASPECT_SEPARATOR + aspect.getDirective());
				aspectFieldEdit.addCompletion(aspect.getCategory() + 
						CATEGORY_ASPECT_SEPARATOR + aspect.getDirective());
			}
		}
	}
	
	/**
	 * Sets the severities into the form.
	 * 
	 * @param severities
	 */
	public void setSeverities(List<Severity> severities) {
		this.severities = severities;
		
		severity.removeAllItems();
		for (Severity sev: severities) {
			severity.addItem(sev.getName());
			severityEdit.addItem(sev.getName());
		}
	}
	
	/**
	 * Returns severities
	 * @return used severities
	 */
	public List<Severity> getSeverities() {
		return severities;
	}

	/**
	 * Returns the findings from the table.
	 * 
	 * @return
	 */
	public IdList<Finding> getFindings() {
		return findingModel.getFindings();
	}
	
	@Override
	public void setClock(ScribeClock clock) {
		this.headingLabel.setClock(clock);
	}
	
	private class AddImageAction extends AbstractAction {
		
		private static final long serialVersionUID = 8894113170459128315L;

		@Override
		public void actionPerformed(ActionEvent e) {
			JFileChooser openDialog = new JFileChooser();
			openDialog.setCurrentDirectory(lastDir);
			openDialog.addChoosableFileFilter(new ImageFileFilter());
			openDialog.setMultiSelectionEnabled(true);
			//openDialog.setAcceptAllFileFilterUsed(false);

			//Add the preview pane.
			openDialog.setAccessory(new ImagePreview(openDialog));
			
			glassPane.setFaded(true);
			int choose = openDialog.showOpenDialog(FindingsPanel.this);
			glassPane.setFaded(false);
			
			if (JFileChooser.APPROVE_OPTION == choose) {
				for(File f: openDialog.getSelectedFiles()) {
					URI uri = f.toURI();
						
					DefaultListModel model = 
							editMode ? imagesModelEdit : imagesModel;
						
					JList list = editMode ? screenshotListEdit : screenshotList;
						
					if(!model.contains(uri)) {
						model.addElement(uri);
					}
						
					list.setSelectedValue(uri, true);
							
					lastDir = f;
				}
			}
		}
	}
	
	private class DeleteImageAction extends AbstractAction {
		private static final long serialVersionUID = 588257631330989808L;
		@Override
		public void actionPerformed(ActionEvent e) {
			DefaultListModel model = editMode ? imagesModelEdit : imagesModel;
			JList list = editMode ? screenshotListEdit : screenshotList;
			
			Object[] values = list.getSelectedValues();
			
			for(Object value: values) {
				model.removeElement(value);
				if(value.equals(imageIsShown))
					showImageAction.closeViewer();
			}
		}
		
	}
	
	public class ShowImageAction extends AbstractAction {
		private static final long serialVersionUID = -2467886849128385861L;
		private ImageViewer d;
		public void closeViewer() {
			if(d != null) {
				d.dispose();
				imageIsShown = null;
			}
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			int index;
			
			if (editMode) {
				index = screenshotListEdit.getSelectedIndex();
			} else {
				index = screenshotList.getSelectedIndex();
			}
			
			if (index != -1) {
				URI element;
				
				if (editMode) {
					element = (URI)imagesModelEdit.get(index);
				} else {
					element = (URI)imagesModel.get(index);
				}
				if(d == null)
					d = new ImageViewer(FindingsPanel.this);
				
				imageIsShown = element;
				
				d.setImageFile(new File(element));
				d.addWindowListener(new WindowAdapter() {
					@Override
					public void windowClosed(WindowEvent e) {
						imageIsShown = null;
					}
				});
				d.setVisible(true);
			}
		}
	}
	
	private class ScreenshotListener implements ListSelectionListener {
		@Override
		public void valueChanged(ListSelectionEvent e) {
			JList currentList = editMode ? screenshotListEdit : screenshotList;
			
			Object[] values = currentList.getSelectedValues();
			
			deleteImageAction.setEnabled(values.length > 0);
			showImageAction.setEnabled(values.length == 1);
		}
	}
	
	private class AddFindingAction extends AbstractAction{
		private static final long serialVersionUID = -4365038535397196587L;
		@Override
		public void actionPerformed(ActionEvent e) {
			int rowIndex = findingModel.addFinding(getNewFinding());
			
			int row = findingsTable.getRowSorter()
					.convertRowIndexToView(rowIndex);
			
			findingsTable.changeSelection(row, -1, false, false);
		}
	}
	
	private class TableSelectionListener implements ListSelectionListener {
		@Override
		public void valueChanged(ListSelectionEvent e) {
			if (editMode) {
				int row = findingsTable.getRowSorter()
						.convertRowIndexToView(editFindingIndex);
				
				findingsTable.getSelectionModel()
						.setSelectionInterval(row, row);
			} else {
				int count = findingsTable.getSelectedRowCount();
				deleteAction.setEnabled(count > 0);
				editAction.setEnabled(count == 1);
			}
		}
	}
	
	private class EditAction extends AbstractAction {
		private static final long serialVersionUID = 9051935334829931616L;
		public EditAction() {
			putValue(AbstractAction.NAME, Messages.getString(
					"PearReview.Scribe.findings.edit"));
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			if(editMode) {
				return;
			}
			
			int count = findingsTable.getSelectedRowCount();
			
			if(count != 1)
				return;
			
			int row = findingsTable.getSelectedRow();
			
			int index = findingsTable.getRowSorter()
					.convertRowIndexToModel(row);
			
			editFindingIndex = index;
			setEditMode(true);
			
			Finding finding = findingModel.getFinding(index);
			editFinding = finding;
			
			setEditFinding(finding);
			setForm(editForm);
			headingLabel.setCaption(Messages.getString(
			"PearReview.Scribe.tabs.findings") + " - " +
					Messages.getString(
							"PearReview.Scribe.findings.edit_caption"), true);
		}
	}
	
	private class DeleteAction extends AbstractAction {
		private static final long serialVersionUID = 4920553196956156448L;
		public DeleteAction() {
			setEnabled(false);
			putValue(AbstractAction.NAME, Messages.getString(
					"PearReview.Scribe.findings.delete"));
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			int[] indizes = findingsTable.getSelectedRows();
			if(indizes == null)
				return;
			Finding[] findings = new Finding[indizes.length];
			/* get selected findings */
			for(int i = 0 ; i < indizes.length ; i++) {
				int modelIndex = findingsTable.getRowSorter()
						.convertRowIndexToModel(indizes[i]);
				findings[i] = findingModel.getFinding(modelIndex);
			}
			
			/* remove selected findings */
			for(int i = 0 ; i < findings.length ; i++) {
				findingModel.removeFinding(findings[i]);
			}
		}
	}
	
	private class EndEditAction extends AbstractAction {
		private static final long serialVersionUID = 3853745936311348114L;
		@Override
		public void actionPerformed(ActionEvent e) {
			setEditMode(false);
			
			findingModel.validateFinding(getEditFinding());
			
			setForm(newForm);
			headingLabel.setCaption(Messages.getString(
					"PearReview.Scribe.tabs.findings"), false);
		}
	}
	
	private class AbortEditAction extends AbstractAction {
		private static final long serialVersionUID = 3684891370282657174L;
		@Override
		public void actionPerformed(ActionEvent e) {
			setEditMode(false);
			
			setForm(newForm);
			headingLabel.setCaption(Messages.getString(
					"PearReview.Scribe.tabs.findings"), false);
			
		}
	}
	
	private class AddAspectAction extends AbstractAction {
		private static final long serialVersionUID = 4970010129639008565L;
		@Override
		public void actionPerformed(ActionEvent e) {
			DefaultListModel model = 
					editMode ? aspectsListModelEdit : aspectsListModel;
			JTextField field = editMode ? aspectFieldEdit : aspectField;
			JList list = editMode ? aspectsListEdit : aspectsList;
			
			Object element;
			
			if (field.getText() == null || field.getText().equals("")) {
				element = Messages.getString(
					"PearReview.Scribe.findings.aspect") + " " + aspectNum;
				aspectNum++;
			} else {
				element = field.getText();
			}
			
			field.setText(null);
			model.addElement(element);
			list.setSelectedValue(element, true);
		}
	}
	
	private class DeleteAspectAction extends AbstractAction {
		private static final long serialVersionUID = 8472112837109371689L;
		@Override
		public void actionPerformed(ActionEvent e) {
			DefaultListModel model = 
					editMode ? aspectsListModelEdit : aspectsListModel;
			JList list = editMode ? aspectsListEdit : aspectsList;
			
			if(list.isSelectionEmpty()) {
				return;
			}
			
			for(Object element: list.getSelectedValues()) {
				model.removeElement(element);
			}
		}
	}
	
	private class ImageFlavorListener implements FlavorListener, Serializable {
		private static final long serialVersionUID = -6064436084789918827L;
		@Override
		public void flavorsChanged(FlavorEvent e) {
			addClipboardImageAction.setEnabled(isClipboardImageAvailable());
		}
	}
	
	private class AddClipboardImageAction extends AbstractAction {
		private static final long serialVersionUID = -5060767493607303973L;
		public AddClipboardImageAction() {
			setEnabled(isClipboardImageAvailable());
			
			putValue(Action.NAME, Messages.getString(
			"PearReview.Scribe.findings.add_image_clipboard"));
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			if(!isClipboardImageAvailable()) {
				this.setEnabled(false);
				return;
			}
			Clipboard clipboard = 
					Toolkit.getDefaultToolkit().getSystemClipboard();
			try {
				/* get image */
				Object data = clipboard.getData(DataFlavor.imageFlavor);
				Image image = (Image) data;
				
				/* create new temp file */
				File tempFile = File.createTempFile("clip", ".jpg");
				//tempFile.deleteOnExit();
				
				int imageWidth = image.getWidth(null);
				int imageHeight = image.getHeight(null);
				int imageType = BufferedImage.TYPE_INT_RGB;
				BufferedImage bufferedImage = new BufferedImage(imageWidth, 
						imageHeight, imageType);
				Graphics2D g2 = bufferedImage.createGraphics();
				g2.drawImage(image, 0, 0, null);
				g2.dispose();
				
				/* save as jpg image */
				ImageIO.write(bufferedImage, "jpg", tempFile);
				
				URI tempFileURI = tempFile.toURI();
				
				if(editMode) {
					imagesModelEdit.addElement(tempFileURI);
				} else {
					imagesModel.addElement(tempFileURI);
				}
				
			} catch (UnsupportedFlavorException e1) {
				// TODO error message?!
				e1.printStackTrace();
			} catch (IOException e1) {
				// TODO error message?!
				e1.printStackTrace();
			}
		}
	}
	
	private class FontChangeListener implements ChangeListener, Serializable {
		private static final long serialVersionUID = -1971767478503395523L;
		@Override
		public void stateChanged(ChangeEvent e) {
			updateFontSize();
		}
	}
	
	private void updateFindingsTableRowHeight() {
		int height = findingsTable.getRowMargin();
		height += ROW_SPACE;
		height += findingsTable.getFontMetrics(findingsTable.getFont())
				.getHeight();
		
		findingsTable.setRowHeight(height);
	}
	
	private void updateFontSize() {
		if(bottom != null) {
			int size = bottom.getFontSize();
			setFontToComponents(this, size);
			
			for(JComponent comp : accordion.getBarComponents())
				setFontToComponents(comp, size);
			
			for(JComponent comp : accordionEdit.getBarComponents())
				setFontToComponents(comp, size);
		}
	}
	
	private void setFontToComponents(Component comp, int fontSize) {
		if(comp == bottom 
					|| comp == headingLabel 
					|| comp instanceof JLabel
					|| comp instanceof JButton) {
			return;
		}
			
		Font font = new Font(comp.getFont().getFontName(), 
				comp.getFont().getStyle(),
				fontSize);
		comp.setFont(font);
		
		if(comp == findingsTable) {
			updateFindingsTableRowHeight();
			return;
		}
		
		if(comp instanceof JComboBox) {
			return;
		}
		
		if(comp instanceof Container) {
			Container cont = (Container) comp;
			for(int i = 0 ; i < cont.getComponentCount(); i++) {
				setFontToComponents(cont.getComponent(i), fontSize);
			}
		}
	}

	@Override
	public String getHint() {
		return Messages.getString("PearReview.hint.scribe.findings");
	}

	@Override
	public String getErrorMessage() {
		return Messages.getString("PearReview.Scribe.tabs.findings_error");
	}
	
	@Override
	public void setNextViewAction(Action action) {
		bottom.setNextViewAction(action);
	}

	@Override
	public void setPreviousViewAction(Action action) {
		bottom.setPreviousViewAction(action);
	}

	@Override
	public int getFontSize() {
		return bottom.getFontSize();
	}
	@Override
	public void setFontSize(int fontSize) {
		if(fontSize >= 0)
			bottom.setFontSize(fontSize);
	}
}
